﻿using Microsoft.AspNetCore.SignalR;
using OA.Infrastructure.Authentication.Redis;
using OA.Infrastructure.DomainModels.TemporaryAuthorization;
using OA.Infrastructure.Impl;
using OA.Infrastructure.Job;
using OA.Infrastructure.SignalR;
using OA.Infrastructure.SignalR.Abstractions;
using OA.Infrastructure.WeCom;
using OA.Infrastructure.WeCom.Abstractions;
using Quartz;

namespace Microsoft.Extensions.DependencyInjection;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddInfrastructure(this IServiceCollection services)
    {
        services.AddScoped<IDepartmentService, DepartmentService>();
        services.AddScoped<IRoleService, RoleService>();
        services.AddScoped<IUserService, UserService>();

        services.AddScoped<ISignalRService, SignalRService>();
        services.AddScoped<IAccountService, AccountService>();

        services.AddScoped<ISystemSettingService, SystemSettingService>();

        services.AddScoped<ITemporaryAuthorizationService<TemporaryAuthorizationCodeModel>, UserSensitiveDataTemporaryAuthorizationService>();

        services.AddSingleton<RedisClient>();

        services.AddWeCom();
        services.AddReplaceSignalR();
        services.AddHttpContextAccessor();

        return services;
    }

    public static IServiceCollection AddWeCom(this IServiceCollection services)
    {
        services.AddOptions<WeComOptions>()
            .Configure<IConfiguration>((opts, cfg) =>
            {
                cfg.Bind(WeComOptions.Position, opts);
            });

        services.AddMemoryCache();
        services.AddSingleton<IWeComService, WeComService>();
        services.AddScoped<IWeComMessageDispatcher, WeComMessageDispatcher>();
        services.RegisterWeComEventSerializers();

        return services;
    }

    public static IServiceCollection AddReplaceSignalR(this IServiceCollection services)
    {
        services.AddSignalR(opts =>
        {
#if DEBUG
            opts.EnableDetailedErrors = true;
#endif
        });
        services.AddSingleton<IUserIdProvider, UserIdentityProvider>();
        services.AddSingleton<IClientProxyFactory, ClientProxyFactory>();

        return services;
    }

    public static IServiceCollection AddIntegrateCors(this IServiceCollection services, params string[] origins)
    {
        var trustIP = Environment.GetEnvironmentVariable("TrustIP");
        var union = string.IsNullOrEmpty(trustIP) ? Enumerable.Empty<string>() : new string[] { trustIP };
        services.AddCors(opts =>
        {
            opts.AddPolicy("__signalRCors", policy =>
            {
                policy
                    .WithOrigins(origins
                        .Union(new string[] { "http://localhost:3100", "http://172.25.13.69:3100" })
                        .Union(union)
                        .ToArray())
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });

        return services;
    }

    public static IServiceCollection AddQuartzCore(this IServiceCollection services, Action<IServiceCollectionQuartzConfigurator>? action = null)
    {
        services.AddQuartz(cfg =>
        {
            cfg.SchedulerId = "Assets Management System - Scheduler";

            cfg.UseSimpleTypeLoader();
            cfg.UseInMemoryStore();
            cfg.UseDefaultThreadPool(x => x.MaxConcurrency = 10);

            cfg.UseMicrosoftDependencyInjectionJobFactory();

            cfg.ScheduleJob<SendNotification>(trigger => trigger
                .WithIdentity(nameof(SendNotification))
                .StartAt(DateTimeOffset.Now.AddMinutes(10))
                .WithDailyTimeIntervalSchedule(builder => builder.WithInterval(10, IntervalUnit.Minute))
                .WithDescription("向客户端发送通知"));

            cfg.ScheduleJob<AskForAdminNotification>(trigger => trigger
                .WithIdentity(nameof(AskForAdminNotification))
                .StartNow()
                .WithDailyTimeIntervalSchedule(builder => builder.WithInterval(3, IntervalUnit.Minute))
                .WithDescription("向管理员发送通知"));

            action?.Invoke(cfg);
        });

        services.AddQuartzHostedService(opts => opts.WaitForJobsToComplete = true);
        services.AddQuartzServer(cfg => cfg.WaitForJobsToComplete = true);

        return services;
    }
}
